package com.gonsin.license;


import com.gonsin.license.processors.LicenseLocalProcessor;
import com.gonsin.license.processors.LicenseRemoteProcessor;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.quartz.JobDataMap;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static com.gonsin.license.GLicenseAutoSelector.DEVICE;

@Slf4j
@Configuration
public class LicenseConfig implements InitializingBean {

    /**
     * 是否输出日志
     */
    public static boolean LOG = false;


    // 是否已授权
    public static boolean licensed;

    // 机器码
    public static String uuid;

    @Getter
    @Value("${com.gonsin.license.filePath:/home/gonsin/}")
    private String filePath = "/home/gonsin/";

    @Getter
    @Value("${com.gonsin.license.debug:false}")
    private boolean debug = false;

    @Value("${com.gonsin.license.licenseUrl:http://update.gonsincloud.com/api/getLicense}")
    private String licenseUrl;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private LicenseLocalProcessor localProcessor;
    @Autowired
    private LicenseRemoteProcessor remoteProcessor;

    @Value("${com.gonsin.license.licenseServer:http://update.gonsincloud.com}")
    private String licenseServer;


    @Override
    public void afterPropertiesSet() throws Exception {
        if(debug){
            licensed = true;
            return;
        }
        String device = DEVICE;

        try {
//            File temp = new File(tempPath);
//            if(!temp.exists()){
//                temp.mkdirs();
//            }

            String id = MainBordUtil.getMainBordId().toUpperCase();
            if(StringUtils.isEmpty(id)){
                File mainBoardFile = new File(filePath + "mainBoard");
                if(mainBoardFile.exists()){
                    id = FileUtils.readFileToString(mainBoardFile, StandardCharsets.UTF_8);
                } else {
                    id = RandomStringUtils.random(32, true ,true);
                    if(!mainBoardFile.createNewFile()){
                        log.warn("can not create main board file");
                        licensed = false;
                        return;
                    }
                    FileUtils.writeStringToFile(mainBoardFile, id, StandardCharsets.UTF_8);
                }
            }
            String md5;


            // 查询本地是否有授权信息
            File licensePath = new File(filePath + "license");
            if(!licensePath.exists()){
                licensePath.mkdirs();
            }

            File deviceFile = new File(filePath + "device");
            if(deviceFile.exists()){
                md5 = Md5Utils.getMD5(id).toUpperCase();
                this.uuid = md5;
                if(!deviceFile.delete()){
                    log.warn("can not create device file, as device delete error");
                    licensed = false;
                    return;
                }
            } else {
                // 为了兼容旧版，先查看旧版的文件是否存在，如果不存在才使用新版的文件位置
                deviceFile = new File(filePath + "license" + File.separator + "device");
                if(!deviceFile.exists()){
                    md5 = Md5Utils.getMD5(RandomStringUtils.random(32, true, true)).toUpperCase();
                    this.uuid = md5;
                    // 如果没有授权文件，则生成设备文件
                    FileUtils.writeStringToFile(deviceFile, md5, "UTF8");
                } else {
                    md5 = FileUtils.readFileToString(deviceFile, "UTF8").toUpperCase();
                    this.uuid = md5;
                }
            }

            // 如果本地文件存在，则从本地查询授权信息
            File license = new File(filePath + "license/" + device + "_license");
            if(license.exists()){
                licensed = this.localProcessor.validateLicense(this.uuid, license);
                return;
            }

            // 如果本地文件不存在，则从服务器查询授权信息
            licensed = this.remoteProcessor.validateLicense(this.uuid);

        } catch (Exception ex){
            log.error(ex.toString(), ex);
        }

    }

    public boolean isLicensed() {
        return licensed;
    }

    public String getUuid() {
        return uuid;
    }

    public Map<String,Object> getLicenseFileInfo() throws Exception{
        Map<String,Object> result = new HashMap<>();
        File license = new File(filePath + "license/" + DEVICE + "_license");
        if(license.exists()){
            result = this.localProcessor.getLicenseFileInfo(uuid, license);
        }
        return result;
    }

    /**
     * 校验授权文件
     * @param license
     * @return
     */
    public int validateLicenseFile(File license) throws Exception {
        if(!license.exists()){
            licensed = false;
            return LicenseResult.LICENSE_FAIL_0;
        }
        licensed = this.localProcessor.validateLicense(this.uuid, license);
        if(licensed){
            FileUtils.copyFile(license, new File(filePath + "license/" + DEVICE + "_license"));
            return LicenseResult.SUCCESS;
        }

        return LicenseResult.LICENSE_FAIL_1;
    }

    /**
     * 网页上授权
     */
    public int validateLicenseOnline(String code) {
        String device = DEVICE;
        CloseableHttpClient client = HttpClientBuilder.create().build();
        long now = System.currentTimeMillis();
        HttpPost post = new HttpPost(licenseUrl);
        if(LOG){
            log.info("请求：" + post.getURI());
        }
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("licenseKey", code));
        LicenseResponse response = null;
        try {
            post.setEntity(new UrlEncodedFormEntity(params));
            response = client.execute(post, response1 -> {
                InputStream input = response1.getEntity().getContent();

                StringBuilder sb = new StringBuilder();
                String line;
                BufferedReader br = new BufferedReader(new InputStreamReader(input));
                while ((line = br.readLine()) != null) {
                    sb.append(line);
                }
                String str = sb.toString();
                if(LOG){
                    log.info("返回：" + str);
                }

                JsonParser parser = new JsonParser();
                JsonElement element = parser.parse(str);
                JsonObject responseJson = element.getAsJsonObject();
                if(responseJson == null){
                    return null;
                }
                int status = responseJson.get("status").getAsInt();
                if(status != 200){
                    return null;
                }

                JsonObject dataJson = responseJson.get("data").getAsJsonObject();
                String licenseKey = dataJson.get("licenseKey").getAsString();
                String date = dataJson.get("date").getAsString();
                String company = dataJson.get("company").getAsString();
                String uuid = dataJson.get("uuid").getAsString();
                String tempDevice = dataJson.get("device").getAsString();
                String licenseUrl = dataJson.get("licenseUrl").getAsString();

                LicenseResponse licenseResponse = new LicenseResponse();
                licenseResponse.setCompany(company);
                licenseResponse.setDate(date);
                licenseResponse.setStatus(200);
                licenseResponse.setUuid(uuid);
                licenseResponse.setDevice(tempDevice);
                licenseResponse.setLicenseUrl(licenseUrl);
                return licenseResponse;
            });
        } catch (Exception e) {
            log.error(e.toString(), e);
        }

        if(response == null){
            return LicenseResult.LICENSE_FAIL_5;
        }

        if(response.getStatus() != 200){
            return LicenseResult.LICENSE_FAIL_6;
        }

        // 比较本地信息
        if(!device.equals(response.getDevice())){
            return LicenseResult.LICENSE_FAIL_2;
        }
        if(!uuid.equals(response.getUuid())){
            return LicenseResult.LICENSE_FAIL_1;
        }
        if(!response.getDate().equals("forever")){
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
            Date date = null;
            try {
                date = sdf.parse(response.getDate());
                if(date.getTime() < System.currentTimeMillis()){
                    return LicenseResult.LICENSE_FAIL_4;
                }
            } catch (ParseException e) {
                log.error(e.toString(), e);
            }
        }

        // 授权成功，将授权文件下载到本地
        if(HttpUtils.downloadFile(licenseServer + response.getLicenseUrl(),
                filePath + "license/" + DEVICE + "_license")){
            File licenseFile = new File(filePath + "license/" + DEVICE + "_license");
            try {
                if(localProcessor.validateLicense(uuid, licenseFile)){
                    licensed = true;
                    return LicenseResult.SUCCESS;
                }
            } catch (Exception e) {
                return LicenseResult.LICENSE_FAIL_6;
            }
            licenseFile.delete();
        }
        return LicenseResult.LICENSE_FAIL_7;

    }

    /**
     * 修改授权到期时间
     * @param date 新的到期时间  如2025/05/30
     */
    public int modifyAuthExpirationTime(String date) throws Exception{
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String formattedTime = now.format(formatter);
        File license = new File(filePath + "license/" + DEVICE + "_license");
        if(!license.exists()){
            licensed = false;
            return LicenseResult.LICENSE_FAIL_0;
        }
        Map<String,Object> decryptionInfo = this.localProcessor.getLicenseFileInfo(uuid, license);
        decryptionInfo.put("validate",date);
        String json = new Gson().toJson(decryptionInfo);
        String firstEncryptAES = AESUtil.encryptAES(json,"gonsin", "gonsin");
        firstEncryptAES = firstEncryptAES + "A" + uuid;
        String newSecret = AESUtil.encryptAES(firstEncryptAES, "gonsin", "gonsin");
        FileUtils.copyFile(license,new File(filePath + "license/" + DEVICE + "_license_"+formattedTime));
        FileUtils.delete(license);
        FileUtils.writeStringToFile(license, newSecret, "UTF8");
        this.localProcessor.createDelayExpireJob(date);
        return LicenseResult.SUCCESS;
    }
}
